package com.cloud.service.assetsdetail.impl;

import com.alibaba.fastjson.JSONObject;
import com.cloud.commons.constants.ConsumeConstant;
import com.cloud.dao.assetsdetail.AssetsDetailDao;
import com.cloud.model.entity.assets.Assets;
import com.cloud.model.entity.assetsdetail.AssetsDetail;
import com.cloud.model.entity.consumetype.ConsumeType;
import com.cloud.model.view.assets.AssetsView;
import com.cloud.model.view.assetsdetail.AssetsDetailView;
import com.cloud.model.view.comsumepie.ComsumePieView;
import com.cloud.model.view.consumetype.ConsumeTypeView;
import com.cloud.service.assetsdetail.AssetsDetailService;
import com.cloud.commons.utils.CloudCopyUtils;
import com.cloud.service.assets.AssetsService;
import com.cloud.commons.utils.DateUtils;
import com.cloud.dao.bookkeeping.BookkeepingDao;
import com.cloud.dao.assets.AssetsDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * <b><code>AssetsDetailImpl</code></b>
 * <p/>
 * AssetsDetail的具体实现
 * <p/>
 * <b>Creation Time:</b> 2019-10-15 17:22:19.
 *
 * @author ${model.author}
 * @version 1.0.0
 * @since cloud-spring-boot-be 1.0.0
 */
@Service
public class AssetsDetailServiceImpl implements AssetsDetailService {

    /**
     * The Constant LOG.
     */
    private static final Logger LOG = LoggerFactory
            .getLogger(AssetsDetailServiceImpl.class);

    @Autowired
    private AssetsDetailDao assetsDetailDao;

    @Autowired
    private AssetsService assetsService;

    @Autowired
    private BookkeepingDao bookkeepingDao;

    @Autowired
    private AssetsDao assetsDao;

    @Autowired
    private AssetsDetailService assetsDetailService;

    @Override
    public AssetsDetailView getEntity(long id) {
        // 获取Entity
        AssetsDetail assetsDetail = assetsDetailDao.findById(id).orElseThrow(() -> new RuntimeException("获取不到id为：" + id + "的数据记录"));
        // 复制Dao层属性到view属性
        AssetsDetailView assetsDetailView = new AssetsDetailView();
        CloudCopyUtils.copyBean(assetsDetail, assetsDetailView);
        return assetsDetailView;
    }

    @Override
    public long getEntitiesCount() {
        return assetsDetailDao.count();
    }

    @Override
    public List<AssetsDetailView> findAll() {
        List<AssetsDetailView> assetsDetailViews = new ArrayList<>();
        List<AssetsDetail> assetsDetails = assetsDetailDao.findAll();
        for (AssetsDetail assetsDetail : assetsDetails) {
            AssetsDetailView assetsDetailView = new AssetsDetailView();
            CloudCopyUtils.copyBean(assetsDetail, assetsDetailView);
            assetsDetailViews.add(assetsDetailView);
        }
        return assetsDetailViews;
    }

    @Override
    public AssetsDetailView saveEntity(AssetsDetailView assetsDetailView) {
        // 保存的业务逻辑
        AssetsDetail assetsDetail = new AssetsDetail();
        CloudCopyUtils.copyBean(assetsDetailView, assetsDetail);
        // user数据库映射传给dao进行存储
        assetsDetail.setCreateTime(System.currentTimeMillis());
        assetsDetail.setUpdateTime(System.currentTimeMillis());
        assetsDetail.setWeight(System.currentTimeMillis());
        assetsDetail.setEnabled(1);
        assetsDetailDao.save(assetsDetail);
        CloudCopyUtils.copyBean(assetsDetail, assetsDetailView);
        return assetsDetailView;
    }

    @Override
    public void deleteEntity(long id) {
        AssetsDetail assetsDetail = assetsDetailDao.findById(id).orElseThrow(() -> new RuntimeException("获取不到id为：" + id + "的数据记录"));
        assetsDetail.setId(id);
        assetsDetailDao.delete(assetsDetail);
    }

    @Override
    @Transactional(rollbackOn = {Exception.class})
    public void deleteEntities(String ids) {
        String[] entityIds = ids.split("\\,");
        List<AssetsDetail> assetsDetails = new ArrayList<>();
        for (String entityId : entityIds) {
            AssetsDetail assetsDetail = new AssetsDetail();
            assetsDetail.setId(Long.valueOf(entityId));
            assetsDetails.add(assetsDetail);
        }
        assetsDetailDao.deleteInBatch(assetsDetails);
    }

    @Override
    public void updateEntity(AssetsDetailView assetsDetailView) {
        Specification<AssetsDetail> assetsDetailSpecification = Optional.ofNullable(assetsDetailView).map(s -> {
            return new Specification<AssetsDetail>() {
                @Override
                public Predicate toPredicate(Root<AssetsDetail> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                    List<Predicate> predicates = new ArrayList<>();
                    // id
                    predicates.add(criteriaBuilder.equal(root.get("id").as(Long.class), s.getId()));

                    criteriaQuery.where(predicates.toArray(new Predicate[predicates.size()]));
                    return criteriaQuery.getRestriction();
                }
            };
        }).orElseThrow(() -> new IllegalArgumentException("AssetsDetailView is null"));


        // 获取原有的属性，把不变的属性覆盖
        Optional<AssetsDetail> assetsDetailOptionalBySearch = assetsDetailDao.findOne(assetsDetailSpecification);
        assetsDetailOptionalBySearch.map(assetsDetailBySearch -> {
            CloudCopyUtils.copyBeanExcludeNull(assetsDetailView, assetsDetailBySearch);
            assetsDetailBySearch.setUpdateTime(System.currentTimeMillis());
            assetsDetailDao.save(assetsDetailBySearch);
            return "";
        }).orElseThrow(() -> new RuntimeException("无法找到id为" + assetsDetailView.getId() + "的数据记录"));
    }

    @Override
    @Transactional
    public void saveAssetsAndAssetsDetail(Long userId) {

        Assets assets = assetsDao.findByUserId(userId);
        AssetsView assetsView = new AssetsView();
        if (!ObjectUtils.isEmpty(assets)) {
            // 存在则复制
            CloudCopyUtils.copyBean(assets, assetsView);
        } else {
            // 不存在新建数据
            assetsView = createAssetsView(userId);
        }


        Long monthFirstDay = DateUtils.getCurrentMonthFirstDay(System.currentTimeMillis());
        AssetsDetail assetsDetail = assetsDetailDao.findByAssetsIdAndNowFirstMonth(assetsView.getId(), monthFirstDay);
        if (ObjectUtils.isEmpty(assetsDetail)) {
            // 不存在新建数据
            createAssetsDetailView(assetsView.getId(), userId);

        }


    }

    private void createAssetsDetailView(Long assetsId, Long userId) {
        AssetsDetailView assetsDetailView = new AssetsDetailView();
        assetsDetailView.setAssetsId(assetsId);
        assetsDetailView.setUserId(userId);
        assetsDetailView.setMonthTotalExpenditure(ConsumeConstant.MONRY_INIT);
        assetsDetailView.setMonthTotalMoney(ConsumeConstant.MONRY_INIT);
        assetsDetailView.setMonthTotalIncome(ConsumeConstant.MONRY_INIT);
        assetsDetailView.setNowMonth(DateUtils.getYearAndMonth(System.currentTimeMillis()));
        assetsDetailView.setNowFirstMonth(DateUtils.getCurrentMonthFirstDay(System.currentTimeMillis()));
        this.saveEntity(assetsDetailView);
    }

    private AssetsView createAssetsView(Long userId) {
        AssetsView assetsView = new AssetsView();
        assetsView.setUserId(userId);
        assetsView.setTotalMoney(ConsumeConstant.MONRY_INIT);
        assetsView.setTotalIncome(ConsumeConstant.MONRY_INIT);
        assetsView.setTotalExpenditure(ConsumeConstant.MONRY_INIT);
        assetsView = assetsService.saveEntity(assetsView);
        return assetsView;
    }

    @Override
    @Transactional
    public void updateMonyByUserIdAndConsumeTime(Long userId, Long consumeTime) {
        Long startTime = DateUtils.getCurrentMonthFirstDay(consumeTime);
        Long endTime = DateUtils.getCurrentMonthLastDay(consumeTime);
        AssetsDetail assetsDetail = assetsDetailDao.findByUserIdAndNowFirstMonth(userId, startTime);
        if (ObjectUtils.isEmpty(assetsDetail)) {
            // 获取不到数据，重新新建数据信息
            this.saveAssetsAndAssetsDetail(userId);
            assetsDetail = assetsDetailDao.findByUserIdAndNowFirstMonth(userId, startTime);
        }
        Map<String, Long> bookkeepingMap = bookkeepingDao.sunByUserIdAndConsumeTimeBetween(userId, startTime, endTime);

        Long income = !ObjectUtils.isEmpty(bookkeepingMap.get("income")) ? Long.valueOf(String.valueOf(bookkeepingMap.get("income"))) : 0L;
        Long expenditure = !ObjectUtils.isEmpty(bookkeepingMap.get("expenditure")) ? Long.valueOf(String.valueOf(bookkeepingMap.get("expenditure"))) : 0L;
        Long money = income - expenditure;

        // 更新月收入
        AssetsDetailView assetsDetailView = new AssetsDetailView();
        assetsDetailView.setMonthTotalIncome(income);
        assetsDetailView.setMonthTotalExpenditure(expenditure);
        assetsDetailView.setMonthTotalMoney(money);
        assetsDetailView.setId(assetsDetail.getId());
        assetsDetailService.updateEntity(assetsDetailView);

        // 更新总收入
        Map<String, Long> assetsDetailMap = assetsDetailDao.sunMoneyByAssetsId(assetsDetail.getAssetsId());
        Long totalIncome = Long.valueOf(String.valueOf(assetsDetailMap.get("income")));
        Long totalExpenditure = Long.valueOf(String.valueOf(assetsDetailMap.get("expenditure")));
        Long totalMoney = Long.valueOf(String.valueOf(assetsDetailMap.get("money")));
        AssetsView assetsView = new AssetsView();
        assetsView.setId(assetsDetail.getAssetsId());
        assetsView.setTotalIncome(totalIncome);
        assetsView.setTotalExpenditure(totalExpenditure);
        assetsView.setTotalMoney(totalMoney);
        assetsService.updateEntity(assetsView);
    }

    @Override
    public AssetsDetailView getEntityByUserId(Long userId) {
        Long monthFirstDay = DateUtils.getCurrentMonthFirstDay(System.currentTimeMillis());
        AssetsDetail assetsDetail = assetsDetailDao.findByUserIdAndNowFirstMonth(userId, monthFirstDay);
        if (ObjectUtils.isEmpty(assetsDetail)) {
            throw new RuntimeException("出现并发，获取不到用户id：" + userId + "的数据信息");
        }
        AssetsDetailView assetsDetailView = new AssetsDetailView();
        CloudCopyUtils.copyBean(assetsDetail, assetsDetailView);
        return assetsDetailView;
    }

    @Override
    public AssetsDetailView getAssetsDetailViewByValueMonthAndUserId(Long userId, Long valueTime) {
        // 获取指定时间当时的月份
        List<Long> nowTimesValue = DateUtils.getDayByValueMonth(valueTime);
        // 获取这个月开始时间戳
        Long startTimeValue = nowTimesValue.get(0);
        // 获取这个月结束时间戳
        Long endTimeValue = nowTimesValue.get(nowTimesValue.size() -1);
        // 通过指定时间月初，用户id,指定时间月所有的天数查询指定月每天消费情况
        List<Map<String, Object>> totalDay = assetsDetailDao.findByNowFirstMonthAndUserIdAndMonthValues(startTimeValue, userId, nowTimesValue);
        // 横纵标表示数值
        List<String> categories = new ArrayList<>();
        // 每天总消费数据
        List<Integer> totalMoneys = new ArrayList<>();
        // 每天支出数据
        List<Integer> pays = new ArrayList<>();
        // 每天收入数据
        List<Integer> incomes = new ArrayList<>();
        for (int i = 0; i < nowTimesValue.size(); i++) {
            Map<String, Object> objectMap = totalDay.get(i);
            String categorie = String.valueOf(objectMap.get("categorie"));
            Integer totalMoney = String.valueOf(objectMap.get("totalMoney")).equals("0") ? 0 : Integer.parseInt(objectMap.get("totalMoney") + "") / 100;
            Integer pay = String.valueOf(objectMap.get("pay")).equals("0") ? 0 : Integer.parseInt(objectMap.get("pay") + "") / 100;
            Integer income = String.valueOf(objectMap.get("income")).equals("0") ? 0 : Integer.parseInt(objectMap.get("income") + "") / 100;
            categories.add(categorie);
            totalMoneys.add(totalMoney);
            pays.add(pay);
            incomes.add(income);
        }
        // 获取这个月份的消费分类情况
        List<ComsumePieView> consumeTypePay = bookkeepingDao.countMoneyByConsumeTimeAndUserId(userId,startTimeValue,endTimeValue,ConsumeConstant.PAY);
        List<ComsumePieView> consumeTypeInCome = bookkeepingDao.countMoneyByConsumeTimeAndUserId(userId,startTimeValue,endTimeValue,ConsumeConstant.INCOME);
        AssetsDetailView assetsDetailView = new AssetsDetailView();
        assetsDetailView.setCategories(categories);
        assetsDetailView.setIncomes(incomes);
        assetsDetailView.setPays(pays);
        assetsDetailView.setTotalMoneys(totalMoneys);
        assetsDetailView.setConsumePayProportion(consumeTypePay);
        assetsDetailView.setConsumeIncomeProportion(consumeTypeInCome);
        // 获取当前用户有效的消费时间
        Long starTime = !ObjectUtils.isEmpty(bookkeepingDao.findOneByUserIdAndEnabledOrderByConsumeTimeAsc(userId,ConsumeConstant.ENABLED)) ? bookkeepingDao.findOneByUserIdAndEnabledOrderByConsumeTimeAsc(userId,ConsumeConstant.ENABLED)  : System.currentTimeMillis() ;
        String billStartTime = DateUtils.timeStamp2Date(String.valueOf(starTime),ConsumeConstant.DATE_TIME_FORMAT);
        String billEndTime = DateUtils.timeStamp2Date(String.valueOf(System.currentTimeMillis()),ConsumeConstant.DATE_TIME_FORMAT);

        assetsDetailView.setBillStartTime(billStartTime);
        assetsDetailView.setBillEndTime(billEndTime);
        return assetsDetailView;
    }
}
